package com.chen.solution.rpc.account.svc.controller;

import com.chen.solution.rpc.account.api.constant.AccountConstant;
import com.chen.solution.rpc.account.api.dto.*;
import com.chen.solution.rpc.account.svc.service.AccountService;
import com.chen.solution.rpc.commonlib.api.BaseResponse;
import com.chen.solution.rpc.commonlib.auth.AuthConstant;
import com.chen.solution.rpc.commonlib.auth.AuthContext;
import com.chen.solution.rpc.commonlib.auth.Authorize;
import com.chen.solution.rpc.commonlib.auth.PermissionDeniedException;
import com.chen.solution.rpc.commonlib.env.EnvConfig;
import com.chen.solution.rpc.commonlib.env.EnvConstant;
import com.chen.solution.rpc.commonlib.error.BusinessServiceException;
import com.chen.solution.rpc.commonlib.validation.PhoneNumber;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;

/**
 * @author ChenTian
 * @date 2022/4/10
 */
@Slf4j
@RestController
@RequestMapping(AccountConstant.ACCOUNT_V1+"/account")
@Validated
public class AccountController {

    @Resource
    private EnvConfig envConfig;
    @Resource
    private AccountService accountService;

    /**
     * 创建新账户
     */
    @PostMapping(path = "/create")
    @Authorize(value = {
            AuthConstant.AUTHORIZATION_SUPPORT_USER,
            AuthConstant.AUTHORIZATION_DEMO_WEB_SERVICE
    })
    public GenericAccountResponse createAccount(@RequestBody @Valid CreateAccountRequest request){
        AccountDto accountDto = accountService.create(request.getName(), request.getEmail(), request.getPhoneNumber());
        GenericAccountResponse response = new GenericAccountResponse(accountDto);
        return response;
    }

    /**
     * 获取或创建（如不存在）账户
     * GetOrCreate is for internal use by other APIs to match a user based on their phoneNumber or email.
     */
    @PostMapping(path= "/getOrCreate")
    @Authorize(value = {
            AuthConstant.AUTHORIZATION_SUPPORT_USER,
            AuthConstant.AUTHORIZATION_DEMO_WEB_SERVICE
    })
    public GenericAccountResponse getOrCreateAccount(@RequestBody @Valid GetOrCreateRequest request){
        AccountDto accountDto = accountService.getOrCreate(request.getName(), request.getEmail(), request.getPhoneNumber());
        GenericAccountResponse response = new GenericAccountResponse(accountDto);
        return response;
    }

    /**
     * 获取现有账户列表（内部使用）
     */
    @GetMapping(path = "/list")
    @Authorize(value = {
            AuthConstant.AUTHORIZATION_SUPPORT_USER
    })
    public ListAccountResponse listAccounts(@RequestParam int offset, @RequestParam @Min(0) int limit){
        AccountList accountList = accountService.list(offset, limit);
        ListAccountResponse response = new ListAccountResponse(accountList);
        return response;
    }

    /**
     * 通过用户ID获取已有账户
     */
    @GetMapping(path = "/get")
    @Authorize(value = {
            AuthConstant.AUTHORIZATION_DEMO_WEB_SERVICE,
            AuthConstant.AUTHORIZATION_AUTHENTICATED_USER,
            AuthConstant.AUTHORIZATION_SUPPORT_USER,
            AuthConstant.AUTHORIZATION_SUPERPOWERS_SERVICE
    })
    public GenericAccountResponse getAccount(@RequestParam @NotBlank String userId){
        this.validateAuthenticatedUser(userId);
        this.validateEnv();

        AccountDto accountDto = accountService.get(userId);

        GenericAccountResponse response = new GenericAccountResponse(accountDto);
        return response;
    }

    /**
     * 通过电话号码获取已有账户
     */
    @GetMapping(path = "/getAccountByPhoneNumber")
    @Authorize(value = {
            AuthConstant.AUTHORIZATION_SUPPORT_USER,
            AuthConstant.AUTHORIZATION_DEMO_WEB_SERVICE
    })
    public GenericAccountResponse getAccountByPhoneNumber(@RequestParam @PhoneNumber String phoneNumber){

        AccountDto accountDto = accountService.getAccountByPhoneNumber(phoneNumber);
        GenericAccountResponse response = new GenericAccountResponse(accountDto);
        return response;
    }

    /**
     * 更新账户
     */
    @PutMapping(path = "/update")
    @Authorize(value = {
            AuthConstant.AUTHORIZATION_DEMO_WEB_SERVICE,
            AuthConstant.AUTHORIZATION_AUTHENTICATED_USER,
            AuthConstant.AUTHORIZATION_SUPPORT_USER,
            AuthConstant.AUTHORIZATION_SUPERPOWERS_SERVICE
    })
    public GenericAccountResponse updateAccount(@RequestBody @Valid AccountDto newAccount){
        this.validateAuthenticatedUser(newAccount.getId());
        this.validateEnv();

        AccountDto accountDto = accountService.update(newAccount);

        GenericAccountResponse response = new GenericAccountResponse(accountDto);
        return response;
    }

    /**
     * 更新密码
     */
    @PutMapping(path = "/updatePassword")
    @Authorize(value = {
            AuthConstant.AUTHORIZATION_AUTHENTICATED_USER,
            AuthConstant.AUTHORIZATION_SUPPORT_USER
    })
    public BaseResponse updatePassword(@RequestBody @Valid UpdatePasswordRequest request){
        this.validateAuthenticatedUser(request.getUserId());

        accountService.updatePassword(request.getUserId(), request.getPassword());

        BaseResponse baseResponse = new BaseResponse();
        baseResponse.setMessage("password updated");
        return baseResponse;
    }

    /**
     * 校验环境，AUTHORIZATION_SUPERPOWERS_SERVICE 仅允许开发环境访问
     */
    private void validateEnv() {
        if(AuthConstant.AUTHORIZATION_SUPERPOWERS_SERVICE.equals(AuthContext.getAuthz())){
            if(!EnvConstant.ENV_DEV.equals(this.envConfig.getName())){
                log.warn("Development service trying to connect outside development environment");
                throw new PermissionDeniedException("This service is not available outside development environments");
            }
        }
    }

    /**
     * 校验已认证用户获取的用户信息是否匹配
     */
    private void validateAuthenticatedUser(String userId) {
        if(AuthConstant.AUTHORIZATION_AUTHENTICATED_USER.equals(AuthContext.getAuthz())){
            String currentUserId = AuthContext.getUserId();
            if(StringUtils.isEmpty(currentUserId)){
                throw new BusinessServiceException("failed to find current user id");
            }
            if(!userId.equals(currentUserId)){
                throw new PermissionDeniedException("You do not have access to this service");
            }
        }
    }

}
